/**
 * WebSocket连接管理器
 *
 * 功能：
 * - 连接池管理（复用连接）
 * - 自动重连机制
 * - 心跳检测
 * - 消息队列（离线缓存）
 * - 错误处理和降级
 */

interface WebSocketConfig {
  url: string;
  id: string;
  reconnect?: boolean;
  reconnectInterval?: number;
  maxReconnectAttempts?: number;
  heartbeatInterval?: number;
}

interface QueuedMessage {
  data: any;
  timestamp: number;
}

class WebSocketManager {
  private connections = new Map<string, WebSocket>();
  private messageQueues = new Map<string, QueuedMessage[]>();
  private reconnectTimers = new Map<string, NodeJS.Timeout>();
  private heartbeatTimers = new Map<string, NodeJS.Timeout>();
  private reconnectAttempts = new Map<string, number>();
  private configs = new Map<string, WebSocketConfig>();

  /**
   * 建立WebSocket连接
   */
  async connect(url: string, id: string, options?: Partial<WebSocketConfig>): Promise<WebSocket> {
    // 如果连接已存在且正常，直接返回
    const existing = this.connections.get(id);
    if (existing && existing.readyState === WebSocket.OPEN) {
      return existing;
    }

    const config: WebSocketConfig = {
      url,
      id,
      reconnect: true,
      reconnectInterval: 3000,
      maxReconnectAttempts: 5,
      heartbeatInterval: 30000,
      ...options,
    };

    this.configs.set(id, config);

    return new Promise((resolve, reject) => {
      try {
        const ws = new WebSocket(url);

        ws.onopen = () => {
          console.log(`[WebSocket] Connected: ${id}`);
          this.connections.set(id, ws);
          this.reconnectAttempts.set(id, 0);

          // 发送队列中的消息
          this.flushQueue(id);

          // 启动心跳
          this.startHeartbeat(id, config.heartbeatInterval!);

          resolve(ws);
        };

        ws.onerror = (error) => {
          console.error(`[WebSocket] Error: ${id}`, error);
          reject(error);
        };

        ws.onclose = () => {
          console.log(`[WebSocket] Closed: ${id}`);
          this.handleClose(id);
        };

        ws.onmessage = (event) => {
          // 心跳响应
          if (event.data === 'pong') {
            return;
          }

          // 其他消息由外部处理
        };
      } catch (error) {
        console.error(`[WebSocket] Connection failed: ${id}`, error);
        reject(error);
      }
    });
  }

  /**
   * 发送消息
   */
  send(id: string, data: any): void {
    const ws = this.connections.get(id);

    if (ws && ws.readyState === WebSocket.OPEN) {
      try {
        const message = typeof data === 'string' ? data : JSON.stringify(data);
        ws.send(message);
      } catch (error) {
        console.error(`[WebSocket] Send failed: ${id}`, error);
        this.queueMessage(id, data);
      }
    } else {
      // 连接未就绪，加入队列
      this.queueMessage(id, data);
    }
  }

  /**
   * 关闭连接
   */
  disconnect(id: string): void {
    const ws = this.connections.get(id);
    if (ws) {
      ws.close();
      this.connections.delete(id);
    }

    // 清理定时器
    this.stopHeartbeat(id);
    this.stopReconnect(id);

    // 清理队列和配置
    this.messageQueues.delete(id);
    this.configs.delete(id);
    this.reconnectAttempts.delete(id);
  }

  /**
   * 断开所有连接
   */
  disconnectAll(): void {
    this.connections.forEach((_, id) => {
      this.disconnect(id);
    });
  }

  /**
   * 获取连接状态
   */
  getState(id: string): number | null {
    const ws = this.connections.get(id);
    return ws ? ws.readyState : null;
  }

  /**
   * 检查连接是否活跃
   */
  isConnected(id: string): boolean {
    const ws = this.connections.get(id);
    return ws?.readyState === WebSocket.OPEN;
  }

  /**
   * 处理连接关闭
   */
  private handleClose(id: string): void {
    this.connections.delete(id);
    this.stopHeartbeat(id);

    const config = this.configs.get(id);
    if (config?.reconnect) {
      this.attemptReconnect(id);
    }
  }

  /**
   * 尝试重连
   */
  private attemptReconnect(id: string): void {
    const config = this.configs.get(id);
    if (!config) return;

    const attempts = this.reconnectAttempts.get(id) || 0;

    if (attempts >= config.maxReconnectAttempts!) {
      console.error(`[WebSocket] Max reconnect attempts reached: ${id}`);
      return;
    }

    console.log(`[WebSocket] Reconnecting (${attempts + 1}/${config.maxReconnectAttempts}): ${id}`);

    const timer = setTimeout(() => {
      this.reconnectAttempts.set(id, attempts + 1);
      this.connect(config.url, config.id, config).catch((error) => {
        console.error(`[WebSocket] Reconnect failed: ${id}`, error);
      });
    }, config.reconnectInterval);

    this.reconnectTimers.set(id, timer);
  }

  /**
   * 停止重连
   */
  private stopReconnect(id: string): void {
    const timer = this.reconnectTimers.get(id);
    if (timer) {
      clearTimeout(timer);
      this.reconnectTimers.delete(id);
    }
  }

  /**
   * 启动心跳
   */
  private startHeartbeat(id: string, interval: number): void {
    this.stopHeartbeat(id);

    const timer = setInterval(() => {
      const ws = this.connections.get(id);
      if (ws && ws.readyState === WebSocket.OPEN) {
        try {
          ws.send('ping');
        } catch (error) {
          console.error(`[WebSocket] Heartbeat failed: ${id}`, error);
        }
      }
    }, interval);

    this.heartbeatTimers.set(id, timer);
  }

  /**
   * 停止心跳
   */
  private stopHeartbeat(id: string): void {
    const timer = this.heartbeatTimers.get(id);
    if (timer) {
      clearInterval(timer);
      this.heartbeatTimers.delete(id);
    }
  }

  /**
   * 消息加入队列
   */
  private queueMessage(id: string, data: any): void {
    const queue = this.messageQueues.get(id) || [];
    queue.push({
      data,
      timestamp: Date.now(),
    });

    // 限制队列大小（最多100条）
    if (queue.length > 100) {
      queue.shift();
    }

    this.messageQueues.set(id, queue);
    console.log(`[WebSocket] Message queued: ${id}, queue size: ${queue.length}`);
  }

  /**
   * 发送队列中的消息
   */
  private flushQueue(id: string): void {
    const queue = this.messageQueues.get(id);
    if (!queue || queue.length === 0) return;

    const ws = this.connections.get(id);
    if (!ws || ws.readyState !== WebSocket.OPEN) return;

    console.log(`[WebSocket] Flushing queue: ${id}, ${queue.length} messages`);

    while (queue.length > 0) {
      const message = queue.shift();
      if (message) {
        try {
          const data = typeof message.data === 'string' ? message.data : JSON.stringify(message.data);
          ws.send(data);
        } catch (error) {
          console.error(`[WebSocket] Failed to send queued message: ${id}`, error);
          // 重新加入队列头部
          queue.unshift(message);
          break;
        }
      }
    }

    this.messageQueues.set(id, queue);
  }

  /**
   * 获取队列大小
   */
  getQueueSize(id: string): number {
    return this.messageQueues.get(id)?.length || 0;
  }

  /**
   * 清空队列
   */
  clearQueue(id: string): void {
    this.messageQueues.delete(id);
  }
}

// 单例导出
export const wsManager = new WebSocketManager();

// 在窗口关闭时断开所有连接
if (typeof window !== 'undefined') {
  window.addEventListener('beforeunload', () => {
    wsManager.disconnectAll();
  });
}
